#include "LPC11xx.h"
#include "bitops.h"
#include "delay.h"
#include "dht11.h"

static float temperature;
static float humidity;

//初始化DHT11
void dht11_init(void)
{
  //1. 启用IOCONFIG模块
  setbit(LPC_SYSCON->SYSAHBCLKCTRL, 16);
  
  //2. 将PIO1_5引脚配置为GPIO功能
  setbits(LPC_IOCON->PIO1_5, 0, 2, 0);
  
  //3. 启用GPIO模块
  setbit(LPC_SYSCON->SYSAHBCLKCTRL, 6);
  
  //4. 将数据引脚(PIO1_5)配置为输入模式
  clrbit(LPC_GPIO1->DIR, 5);
  
  //DHT11上电后要等待1S 以越过不稳定状态在此期间不能发送任何指令
  delay_ms(1000);
  
  dht11_update();
}

float dht11_temperature(void)
{
  return temperature;
}

float dht11_humidity(void)
{
  return humidity;
}

//读取温湿度
//成功返回0，失败返回非0
int dht11_update(void)
{
  unsigned char data[5];//保存40bit数据
  unsigned char chksum; //校验和
	int i, j;
  
  //发送起始信号
  //将数据引脚设置为输出模式
  setbit(LPC_GPIO1->DIR, 5);
  
  //拉低持续18ms
  clrbit(LPC_GPIO1->DATA, 5);
  delay_ms(18);
  
  //然后设置为输入模式等待DHT11响应
  clrbit(LPC_GPIO1->DIR, 5);
  
  //延时40us等待DHT11响应信号
  delay_us(40);
  
  //判断DHT11是否响应（低电平）
  if (chkbit(LPC_GPIO1->DATA, 5))
  {
    return 1;
  }
  
  //等待响应信号结束（80us低电平+80us高电平）
  while(chkbit(LPC_GPIO1->DATA, 5) == 0);
  while(chkbit(LPC_GPIO1->DATA, 5) != 0);

  //接收字节
	for (j = 0; j < 5; j++)
	{
    //接收bit位
		for (i = 0; i < 8; i++)
		{
			int low_count = 0;
			int high_count = 0;
			//统计低电平持续时间
			while(chkbit(LPC_GPIO1->DATA, 5) == 0)
			{
				low_count++;
				delay_us(1);
			}
			//统计高电平持续时间
			while(chkbit(LPC_GPIO1->DATA, 5) != 0)
			{
				high_count++;
				delay_us(1);
			}

			if (low_count > high_count)
			{
				//接收bit 0
				data[j] = data[j] & (~(0x80 >> i));
			}
			else
			{
				//接收bit 1
				data[j] = data[j] | (0x80 >> i);
			}
		}
	}

	//等待结束标志结束（50us低电平）
	while(chkbit(LPC_GPIO1->DATA, 5) == 0);

	//计算校验和
	chksum = data[0] + data[1] + data[2] + data[3];
	if (chksum != data[4])
	{
		//校验和出错
		return 2;
	}

	//打印温湿度数据
	//printf("H:%d.%d,T:%d.%d\r\n", data[0], data[1], data[2], data[3]);
  
  humidity = data[0] + data[1] * 0.1;
  temperature = data[2];
  if (data[3] & 0x80)
  {
    temperature = -1 - temperature;
  }
  temperature += (data[3] & 0x0f) * 0.1;

  return 0;
}
